#include <gdnative_api_struct.gen.h>
#include <iostream>

#include  <GLES3/gl3.h>

#include "String.hpp"
#include "Array.hpp"
#include "PoolArray.hpp"


int print_shader_info_log (GLuint shader)
{
    GLint length;
    glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &length );
    if (length)
    {
        char* buffer = new char[length];
        glGetShaderInfoLog(shader,length,NULL,buffer);
        printf("%s",buffer);
        delete [] buffer;

        GLint success;
        glGetShaderiv( shader, GL_COMPILE_STATUS, &success );
        if ( success != GL_TRUE ){
            glDeleteShader(shader);
            Godot::GODOT_CORE_API->godot_print_error("Shader Err","quick_program_init","RefGPU:MAIN",__LINE__);
            return 0;
        };

    }
    return 1;
}


GLuint load_shader (const char *shader_source,GLenum type)
{
    GLuint  shader = glCreateShader( type );
    glShaderSource  ( shader, 1, &shader_source, NULL );
    glCompileShader ( shader );
    int Flag;
    if(type==GL_VERTEX_SHADER)Flag=print_shader_info_log(shader);
    if(!Flag)return 0;
    return shader;
}



const char fragment_src[] = R"glsl(
    #version 300 es

    void main()
    {
    }
)glsl";


typedef void(*FUN_t)(godot_pool_array_read_access*);
typedef godot_variant (*godot_method)(godot_object *, void *, void *, int, godot_variant **);

const godot_gdnative_ext_nativescript_api_struct *nativescript_api = NULL;

godot_variant quick_program_init(godot_object *p_instance, void *p_method_data, void *p_user_data, int p_num_args, godot_variant **p_args);
godot_variant quick_input(godot_object *p_instance, void *p_method_data, void *p_user_data, int p_num_args, godot_variant **p_args);
godot_variant quick_set_outBuffer_size(godot_object *p_instance, void *p_method_data, void *p_user_data, int p_num_args, godot_variant **p_args);
godot_variant quick_set_input(godot_object *p_instance, void *p_method_data, void *p_user_data, int p_num_args, godot_variant **p_args);
godot_variant quick_copy_data(godot_object *p_instance, void *p_method_data, void *p_user_data, int p_num_args, godot_variant **p_args);
godot_variant quick_run(godot_object *p_instance, void *p_method_data, void *p_user_data, int p_num_args, godot_variant **p_args);
godot_variant quick_destroy(godot_object *p_instance, void *p_method_data, void *p_user_data, int p_num_args, godot_variant **p_args);

using namespace Godot;



///------------------Global_Variable-----------------------
int _vertexBuffers_size=0;
GLuint _gpuOutputBuffer=0,vao=0,_program=0;
GLuint* _vertexBuffers;
GLint* _vertexBuffers_type;

GLuint vertexShader,fragmentShader;

static int64_t _outBuffer_size;


float *gpuMemoryBuffer=NULL;
///-------------------------------------------------------











extern "C" {
    GDCALLINGCONV void *simple_constructor(godot_object *p_instance, void *p_method_data);
    GDCALLINGCONV void simple_destructor(godot_object *p_instance, void *p_method_data, void *p_user_data);
    void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *p_options)
    {

        Godot::GODOT_CORE_API=p_options->api_struct;

        for (int i = 0; i < GODOT_CORE_API->num_extensions; i++)
        {
            switch (GODOT_CORE_API->extensions[i]->type)
            {
                case GDNATIVE_EXT_NATIVESCRIPT:
            {
                nativescript_api = (godot_gdnative_ext_nativescript_api_struct *)GODOT_CORE_API->extensions[i];
            };
            break;

                default:break;
            };
        };

    }

    void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *p_options)
    {
        GODOT_CORE_API = NULL;
        nativescript_api = NULL;
    }

    void GDN_EXPORT godot_nativescript_init(void *p_handle)
    {
        godot_method_attributes attributes = { GODOT_METHOD_RPC_MODE_DISABLED };

        godot_instance_create_func create = { &simple_constructor, NULL, NULL };
        godot_instance_destroy_func destroy = {  &simple_destructor, NULL, NULL };


        nativescript_api->godot_nativescript_register_class(p_handle, "RefGPU", "Reference", create, destroy);


        godot_instance_method quick_program_init_IM = {&quick_program_init, NULL, NULL };
        nativescript_api->godot_nativescript_register_method(p_handle, "RefGPU", "quick_program_init", attributes, quick_program_init_IM);

        godot_instance_method quick_input_IM = {&quick_input, NULL, NULL };
        nativescript_api->godot_nativescript_register_method(p_handle, "RefGPU", "quick_input", attributes, quick_input_IM);

        godot_instance_method quick_set_outBuffer_size_IM = {&quick_set_outBuffer_size, NULL, NULL };
        nativescript_api->godot_nativescript_register_method(p_handle, "RefGPU", "quick_set_outBuffer_size", attributes, quick_set_outBuffer_size_IM);

        godot_instance_method quick_set_input_IM = {&quick_set_input, NULL, NULL };
        nativescript_api->godot_nativescript_register_method(p_handle, "RefGPU", "quick_set_input", attributes, quick_set_input_IM);

        godot_instance_method quick_run_IM = {&quick_run, NULL, NULL };
        nativescript_api->godot_nativescript_register_method(p_handle, "RefGPU", "quick_run", attributes, quick_run_IM);

        godot_instance_method quick_copy_data_IM = {&quick_copy_data, NULL, NULL };
        nativescript_api->godot_nativescript_register_method(p_handle, "RefGPU", "quick_copy_data", attributes, quick_copy_data_IM);

        godot_instance_method quick_destroy_IM = {&quick_destroy, NULL, NULL };
        nativescript_api->godot_nativescript_register_method(p_handle, "RefGPU", "quick_destroy", attributes, quick_destroy_IM);
    }

    GDCALLINGCONV void *simple_constructor(godot_object *p_instance, void *p_method_data)
    {
        return nullptr;
    }

    GDCALLINGCONV void simple_destructor(godot_object *p_instance, void *p_method_data, void *p_user_data)
    {
        if(_program){
            glDeleteBuffers(_vertexBuffers_size,_vertexBuffers);

            glDeleteBuffers(1,&_gpuOutputBuffer);
            glDeleteVertexArrays(1, &vao);

            glDeleteShader(vertexShader);
            glDeleteShader(fragmentShader);
            glDeleteProgram(_program);
        }
        GODOT_CORE_API->godot_free(p_user_data);
    }
}








///------------------quick_program_init-----------------------
godot_variant quick_program_init(godot_object *p_instance, void *p_method_data, void *p_user_data, int p_num_args, godot_variant **p_args)
{
    if(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER)!=0x8cd5){
        GODOT_CORE_API->godot_print_error("GLES 3.0 contxst error",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }

    Variant* arg0=(Variant*)p_args[0];//shader
    Variant* arg1=(Variant*)p_args[1];//Num

    int64_t&& Num=arg1->ValueOfptr<int64_t>();

///----------------------------debug------------------------------
    if(_program){
        GODOT_CORE_API->godot_print_error("Already Init",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }
    else if(p_num_args!=2){
        GODOT_CORE_API->godot_print_error("The number of parameters must be 2",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }
    else if(arg0->get_type()!=GODOT_VARIANT_TYPE_STRING){
        GODOT_CORE_API->godot_print_error("Arg 0 must be string",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }
    else if(arg1->get_type()!=GODOT_VARIANT_TYPE_INT){
        GODOT_CORE_API->godot_print_error("Arg 1 must be int",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }
    else if(!Num>0){
        GODOT_CORE_API->godot_print_error("Arg 1 must greater than 0",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }
///----------------------------debugEND------------------------------

    _vertexBuffers_size=Num;
    _vertexBuffers=new GLuint[Num];
    _vertexBuffers_type=new GLint[Num];

    String&& Str=arg0->ValueOf<String>();
    godot_char_string&& SS=Str.char_string();
    const char* vertex_src=GODOT_CORE_API->godot_char_string_get_data(&SS);

   // printf("\nargs is %s %ld\n",vertex_src,Num);

     vertexShader = load_shader ( vertex_src , GL_VERTEX_SHADER  );
    if(!vertexShader)return Variant(false);

     fragmentShader = load_shader ( fragment_src , GL_FRAGMENT_SHADER );

    _program = glCreateProgram();

    glAttachShader(_program, vertexShader);
    glAttachShader(_program, fragmentShader);


    GLchar *varyings[]={"outValue"};
    glTransformFeedbackVaryings(_program, sizeof(varyings) / sizeof(varyings[0]), varyings, GL_INTERLEAVED_ATTRIBS);


    glGenBuffers(Num, _vertexBuffers);//VBO

    glGenVertexArrays(1,&vao);//VAO
    glBindVertexArray(vao);

    glLinkProgram(_program);

    glGenBuffers(1, &_gpuOutputBuffer);
    glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, _gpuOutputBuffer);


    glUseProgram(_program);
    glEnable(GL_RASTERIZER_DISCARD);

    GLint _ATTRIBUTE_MAX_LENGTH;
    glGetProgramiv(_program,GL_ACTIVE_ATTRIBUTE_MAX_LENGTH,&_ATTRIBUTE_MAX_LENGTH);

    int I=Num;
    GLsizei Ip;GLint Int_t;GLenum TYPE_E;GLchar C;
    while(I--){
        glEnableVertexAttribArray(I);

        glGetActiveAttrib(_program,I,_ATTRIBUTE_MAX_LENGTH,&Ip,&Int_t,&TYPE_E,&C);

        if(TYPE_E==GL_FLOAT){_vertexBuffers_type[I]=1;}
        else if(TYPE_E==GL_FLOAT_VEC2){_vertexBuffers_type[I]=2;}
        else if(TYPE_E==GL_FLOAT_VEC3){_vertexBuffers_type[I]=3;}
    }



    GODOT_CORE_API->godot_char_string_destroy(&SS);
    return Variant(true);
}

///-------------------------------------------------///
///------------------quick_input-----------------------
godot_variant quick_input(godot_object *p_instance, void *p_method_data, void *p_user_data, int p_num_args, godot_variant **p_args){
    if(!_program){
        GODOT_CORE_API->godot_print_error("Not Init",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }
    else if(p_num_args==0){
        GODOT_CORE_API->godot_print_error("MUST input arg",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }



    int idx=p_num_args;

    int p_size=0;
    //int p_type_size;

    float* ARG;

    godot_pool_array_read_access* access;
    FUN_t godot_gdnative_core_api_struct::* FUN;

    //idx=1;
    while(idx--){
        Variant* Var=(Variant*)p_args[idx];
        godot_variant_type TYPE=Var->get_type();
        if(TYPE==GODOT_VARIANT_TYPE_POOL_REAL_ARRAY){
                godot_pool_real_array P=Var->ValueOfptr<godot_pool_real_array>();
                access=GODOT_CORE_API->godot_pool_real_array_read(&P);
                ARG=(float*)PoolRealArray::read_access_get_ptr(access);
                p_size=GODOT_CORE_API->godot_pool_real_array_size(&P);
                FUN=&godot_gdnative_core_api_struct::godot_pool_real_array_read_access_destroy;
            }
            else if(TYPE==GODOT_VARIANT_TYPE_POOL_VECTOR2_ARRAY){
                godot_pool_vector2_array P=Var->ValueOfptr<godot_pool_vector2_array>();
                access=GODOT_CORE_API->godot_pool_vector2_array_read(&P);
                ARG=(float*)PoolVector2Array::read_access_get_ptr(access);
                p_size=GODOT_CORE_API->godot_pool_vector2_array_size(&P)*2;
                FUN=&godot_gdnative_core_api_struct::godot_pool_vector2_array_read_access_destroy;
            }
            else if(TYPE==GODOT_VARIANT_TYPE_POOL_VECTOR3_ARRAY){
                godot_pool_vector3_array P=Var->ValueOfptr<godot_pool_vector3_array>();
                access=GODOT_CORE_API->godot_pool_vector3_array_read(&P);
                ARG=(float*)PoolVector3Array::read_access_get_ptr(access);

                p_size=GODOT_CORE_API->godot_pool_vector3_array_size(&P)*3;
                FUN=&godot_gdnative_core_api_struct::godot_pool_vector3_array_read_access_destroy;
            }
            else{
                GODOT_CORE_API->godot_print_error("ARG error",__func__,"RefGPU:MAIN",__LINE__);
                return Variant(false);
            }






        //printf("\nOP:");
        //printf("\n%d",idx);
       // printf("\n%d",p_size);
        //printf("\n%d",_vertexBuffers_type[idx]);
        //printf("\n%d",p_size*(_vertexBuffers_type[idx]));

       // printf("\n%f %f %f %f\n",ARG[0],ARG[1],ARG[2],ARG[3]);

        glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffers[idx]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*p_size*(_vertexBuffers_type[idx]), ARG, GL_STATIC_DRAW);


        glVertexAttribPointer(idx, _vertexBuffers_type[idx], GL_FLOAT, GL_FALSE, 0, NULL);

           // glUnmapBuffer(GL_ARRAY_BUFFER);

        }

   // glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffers[0]);
        //    float *A=(float*)glMapBufferRange(GL_ARRAY_BUFFER, 0, sizeof(float)*_outBuffer_size, GL_MAP_READ_BIT);
         //   printf("\n%f %f %f %f",A[0],A[1],A[2],A[3]);
//float OPI[]={0.1,0.2,0.3,0.4,0.5};
//glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffers[1]);
//glBufferData(GL_ARRAY_BUFFER, sizeof(float)*5, OPI, GL_STATIC_DRAW);


//glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, NULL);
       // (GODOT_CORE_API->*FUN)(access);
  //  glBindBuffer(GL_ARRAY_BUFFER, _gpuOutputBuffer);
 //   glBufferData(GL_ARRAY_BUFFER, sizeof(float)*outBufferSize_i, NULL, GL_STREAM_DRAW);
  //  glBindBuffer(GL_ARRAY_BUFFER, 0);
 //   glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, _gpuOutputBuffer);

    (GODOT_CORE_API->*FUN)(access);


    return Variant(true);
}

///------------------quick_set_outBuffer_size-----------------------
godot_variant quick_set_outBuffer_size(godot_object *p_instance, void *p_method_data, void *p_user_data, int p_num_args, godot_variant **p_args){
    Variant* arg0=(Variant*)p_args[0];

    if(!_program){
        GODOT_CORE_API->godot_print_error("Not Init",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }
    else if(p_num_args!=1){
        GODOT_CORE_API->godot_print_error("The number of parameters must be 1",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }
    else if(arg0->get_type()!=GODOT_VARIANT_TYPE_INT){
        GODOT_CORE_API->godot_print_error("Arg 0 must be int",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }


    _outBuffer_size=arg0->ValueOfptr<int64_t>();

    if(gpuMemoryBuffer!=NULL)glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);

    glBindBuffer(GL_ARRAY_BUFFER, _gpuOutputBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*_outBuffer_size, NULL, GL_STREAM_DRAW);

    gpuMemoryBuffer=(float*)glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(float)*_outBuffer_size, GL_MAP_READ_BIT);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    return Variant(true);
}







///------------------quick_set_input-----------------------
godot_variant quick_set_input(godot_object *p_instance, void *p_method_data, void *p_user_data, int p_num_args, godot_variant **p_args){

    Variant* arg0=(Variant*)p_args[0];
    int64_t idx=arg0->ValueOfptr<int64_t>();//索引

    Variant* arg1=(Variant*)p_args[1];
    int64_t size_a=arg1->ValueOfptr<int64_t>();//float个数

    Variant* Var=(Variant*)p_args[2];


    if(!_program){
        GODOT_CORE_API->godot_print_error("Not Init",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }
    else if(p_num_args!=3){
        GODOT_CORE_API->godot_print_error("The number of parameters must be 3",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }
    else if(arg0->get_type()!=GODOT_VARIANT_TYPE_INT){
        GODOT_CORE_API->godot_print_error("Arg 0 must be int",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }
    else if(arg1->get_type()!=GODOT_VARIANT_TYPE_INT){
        GODOT_CORE_API->godot_print_error("Arg 1 must be int",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }

    godot_pool_array_read_access* access;
    FUN_t godot_gdnative_core_api_struct::* FUN;

    float* ARG;

        godot_variant_type TYPE=Var->get_type();
        if(TYPE==GODOT_VARIANT_TYPE_POOL_REAL_ARRAY){
                godot_pool_real_array P=Var->ValueOfptr<godot_pool_real_array>();
                access=GODOT_CORE_API->godot_pool_real_array_read(&P);
                ARG=(float*)PoolRealArray::read_access_get_ptr(access);

                FUN=&godot_gdnative_core_api_struct::godot_pool_real_array_read_access_destroy;
            }
            else if(TYPE==GODOT_VARIANT_TYPE_POOL_VECTOR2_ARRAY){
                godot_pool_vector2_array P=Var->ValueOfptr<godot_pool_vector2_array>();
                access=GODOT_CORE_API->godot_pool_vector2_array_read(&P);
                ARG=(float*)PoolVector2Array::read_access_get_ptr(access);

                FUN=&godot_gdnative_core_api_struct::godot_pool_vector2_array_read_access_destroy;
            }
            else if(TYPE==GODOT_VARIANT_TYPE_POOL_VECTOR3_ARRAY){
                godot_pool_vector3_array P=Var->ValueOfptr<godot_pool_vector3_array>();
                access=GODOT_CORE_API->godot_pool_vector3_array_read(&P);
                ARG=(float*)PoolVector3Array::read_access_get_ptr(access);

                FUN=&godot_gdnative_core_api_struct::godot_pool_vector3_array_read_access_destroy;
            }


    (GODOT_CORE_API->*FUN)(access);

   //printf("\nAT set:%f %f %f %f\n",ARG[0],ARG[1],ARG[2],ARG[3]);
    glBindBuffer(GL_ARRAY_BUFFER,_vertexBuffers[idx]);
    glBufferSubData(GL_ARRAY_BUFFER,0,sizeof(float)*size_a,ARG);
    //float *CC=(float*)glMapBufferRange(GL_ARRAY_BUFFER, 0, sizeof(float)*4, GL_MAP_READ_BIT);
    //printf("\nAT set:%f %f %f %f\n",CC[0],CC[1],CC[2],CC[3]);

    return Variant(true);
}

///------------------quick_copy_data-----------------------
godot_variant quick_copy_data(godot_object *p_instance, void *p_method_data, void *p_user_data, int p_num_args, godot_variant **p_args){
    if(!_program){
        GODOT_CORE_API->godot_print_error("Not Init",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }
    else if(p_num_args!=3){
        GODOT_CORE_API->godot_print_error("The number of parameters must be 3",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }


    Variant* arg0=(Variant*)p_args[0];
    int64_t idx=arg0->ValueOfptr<int64_t>();//起始位置

    Variant* arg1=(Variant*)p_args[1];
    int64_t size_a=arg1->ValueOfptr<int64_t>();//float个数

    Variant* Var=(Variant*)p_args[2];

    float* ARG;

    godot_pool_array_read_access* access;
    FUN_t godot_gdnative_core_api_struct::* FUN;

        godot_variant_type TYPE=Var->get_type();
        if(TYPE==GODOT_VARIANT_TYPE_POOL_REAL_ARRAY){
                godot_pool_real_array P=Var->ValueOfptr<godot_pool_real_array>();
                access=GODOT_CORE_API->godot_pool_real_array_read(&P);
                ARG=(float*)PoolRealArray::read_access_get_ptr(access);

                FUN=&godot_gdnative_core_api_struct::godot_pool_real_array_read_access_destroy;
            }
            else if(TYPE==GODOT_VARIANT_TYPE_POOL_VECTOR2_ARRAY){
                godot_pool_vector2_array P=Var->ValueOfptr<godot_pool_vector2_array>();
                access=GODOT_CORE_API->godot_pool_vector2_array_read(&P);
                ARG=(float*)PoolVector2Array::read_access_get_ptr(access);

                FUN=&godot_gdnative_core_api_struct::godot_pool_vector2_array_read_access_destroy;
            }
            else if(TYPE==GODOT_VARIANT_TYPE_POOL_VECTOR3_ARRAY){
                godot_pool_vector3_array P=Var->ValueOfptr<godot_pool_vector3_array>();
                access=GODOT_CORE_API->godot_pool_vector3_array_read(&P);
                ARG=(float*)PoolVector3Array::read_access_get_ptr(access);

                FUN=&godot_gdnative_core_api_struct::godot_pool_vector3_array_read_access_destroy;
            }



   // printf("\nFF:%f %f %f %f\n",gpuMemoryBuffer[0],gpuMemoryBuffer[1],gpuMemoryBuffer[2],gpuMemoryBuffer[3]);
    while(size_a--){
        int64_t I=idx+size_a;
        ARG[I]=gpuMemoryBuffer[I];
    }

    (GODOT_CORE_API->*FUN)(access);

    return Variant(true);
}

///------------------quick_run-----------------------
godot_variant quick_run(godot_object *p_instance, void *p_method_data, void *p_user_data, int p_num_args, godot_variant **p_args){
   if(!_program){
        GODOT_CORE_API->godot_print_error("Not Init",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }
    else if(p_num_args!=1){
        GODOT_CORE_API->godot_print_error("The number of parameters must be 1",__func__,"RefGPU:MAIN",__LINE__);
        return Variant(false);
    }

    Variant* arg_E1=(Variant*)p_args[0];//循环次数
    int64_t N_cycles = arg_E1->ValueOfptr<int64_t>();

    glBeginTransformFeedback(GL_POINTS);
    glDrawArrays(GL_POINTS, 0, N_cycles);
    glEndTransformFeedback();
    glFinish();

    //glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(feedback), feedback);
    //printf("\nTYPE:\n");
   // printf("\n%ld",N_cycles);
    //printf("\n%f",gpuMemoryBuffer[0]);
    //printf("\n%f",gpuMemoryBuffer[1]);
   // printf("\n%f",gpuMemoryBuffer[2]);

    return Variant(true);
}
///

godot_variant quick_destroy(godot_object *p_instance, void *p_method_data, void *p_user_data, int p_num_args, godot_variant **p_args){
    if(_program){
        glDeleteBuffers(_vertexBuffers_size,_vertexBuffers);

        glDeleteBuffers(1,&_gpuOutputBuffer);
        glDeleteVertexArrays(1, &vao);

        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);
        glDeleteProgram(_program);
    }

    return Variant(true);
}
